#include "carpet.h"


Carpet::Carpet(const Mat& img, const CarpetSize& carpet_size)
        : img(img), carpet_size(carpet_size), homobox_topleft(100, 700) 
{
    vector<Point> corner_list = getCarpetCorner();
    homo_matrix = homography(corner_list);
}



// 视角转换函数
cv::Mat Carpet::homography(const vector<Point>& corner) {
    Point top_left = homobox_topleft;
    Point top_right = homobox_topleft + Point(carpet_size.length, 0);
    Point bottom_left = homobox_topleft + Point(0, carpet_size.width);
    Point bottom_right = homobox_topleft + Point(carpet_size.length, carpet_size.width);

    vector<Point2f> src_points;
    for (const auto& p : corner) {
        src_points.push_back(Point2f(p.x, p.y));
    }

    vector<Point2f> dst_points = {
        Point2f(bottom_left.x, bottom_left.y),
        Point2f(top_left.x, top_left.y),
        Point2f(top_right.x, top_right.y),
        Point2f(bottom_right.x, bottom_right.y)
    };

    return findHomography(Mat(src_points), Mat(dst_points));
}

// 获取地毯梯形边界信息
std::vector<Point> Carpet::getCarpetCorner() {
    Mat gray, color_mask, blurred_mask, edges, imgray, blank_img;
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;

    cvtColor(img, gray, COLOR_BGR2GRAY);
    threshold(gray, color_mask, 200, 255, THRESH_BINARY | THRESH_OTSU);
    GaussianBlur(color_mask, blurred_mask, Size(13, 13), 0);
    RobertsEdge(blurred_mask, edges); // 假设RobertsEdge是自定义函数，需要实现
    drawBiggestBox(edges, imgray); // 假设drawBiggestBox是自定义函数，需要实现
    imgray = imgray.clone();
    Mat corner_area = cornerHarris(imgray, 10, 13, 0.04);
    blank_img = Mat::zeros(img.size(), CV_8UC3);
    blank_img.setTo(Scalar(255, 255, 255), corner_area > 0.01 * corner_area.max());

    findContours(blank_img, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

    vector<Point> corner_points;
    for (const auto& cnt : contours) {
        Point2f center;
        float radius;
        minEnclosingCircle(cnt, center, radius);
        corner_points.push_back(Point(center.x, center.y));
    }

    sort(corner_points.begin(), corner_points.end(), [](const Point& a, const Point& b) { return a.x < b.x; });
    vector<Point> sorted_corner_points = corner_points;

    vector<Point> sub_list_1(sorted_corner_points.begin(), sorted_corner_points.begin() + 2);
    sort(sub_list_1.begin(), sub_list_1.end(), [](const Point& a, const Point& b) { return a.y < b.y; });

    vector<Point> sub_list_2(sorted_corner_points.begin() + 2, sorted_corner_points.end());
    sort(sub_list_2.begin(), sub_list_2.end(), [](const Point& a, const Point& b) { return a.y < b.y; });

    vector<Point> corner_list = {
        sub_list_1[1],
        sub_list_1[0],
        sub_list_2[0],
        sub_list_2[1]
    };

    return corner_list;
}

// 将图像像素点转换为俯视图像素点
Vector2d Carpet::transferImgPoint2HomoPoint(const Point& score_point) {
    Vector3d point(score_point.x, score_point.y, 1);
    Vector3d dst_point = homo_matrix * point;
    dst_point /= dst_point[2];
    return Vector2d(dst_point[0], dst_point[1]);
}

// 获取最终得分
double Carpet::getFinalScore(const Point& score_point, bool save_img = false) {
    Vector2d homo_point = transferImgPoint2HomoPoint(score_point);
    double final_score = homo_point[0] - carpet_size.start_line - homobox_topleft.x;

    if (save_img) {
        time_t now = time(0);
        tm* ltm = localtime(&now);
        string timestamp_str = to_string(ltm->tm_year + 1900) +
                                to_string(ltm->tm_mon + 1) +
                                to_string(ltm->tm_mday) +
                                "_" +
                                to_string(ltm->tm_hour) +
                                to_string(ltm->tm_min) +
                                to_string(ltm->tm_sec);

        string file_name = timestamp_str + ".png";
        Mat score_img = img.clone();
        circle(score_img, Point2f(score_point.x, score_point.y), 2, Scalar(0, 255, 255), 2);
        imwrite(file_name, score_img);

        file_name = timestamp_str + "_homo(" + to_string(final_score / 10) + ").png";
        Mat homo_img = img.clone();
        Mat homo_score_img = warpPerspective(homo_img, homo_matrix, Size(homo_img.cols * 2, homo_img.rows * 2));
        circle(homo_score_img, Point2f(homo_point[0], homo_point[1]), 5, Scalar(0, 255, 255), 5);
        imwrite(file_name, homo_score_img);
    }

    return final_score;
}